#ifndef __COMM_H
#define __COMM_H

#define GET_UINT32(p)                                         \
    ((((uint32_t)(p)[0]) << 24) | (((uint32_t)(p)[1]) << 16) | \
        (((uint32_t)(p)[2]) << 8) | ((uint32_t)(p)[3]))

#define PUT_UINT32(p, i)           \
    do {                             \
        (p)[0] = ((i) >> 24) & 0xff; \
        (p)[1] = ((i) >> 16) & 0xff; \
        (p)[2] = ((i) >> 8) & 0xff;  \
        (p)[3] = (i) & 0xff;         \
    } while(0)
#define GET_UINT64(p)                                            \
    ((((uint64_t)(p)[0]) << 56) | (((uint64_t)(p)[1]) << 48) |    \
        (((uint64_t)(p)[2]) << 40) | (((uint64_t)(p)[3]) << 32) | \
        (((uint64_t)(p)[4]) << 24) | (((uint64_t)(p)[5]) << 16) | \
        (((uint64_t)(p)[6]) << 8) | ((uint64_t)(p)[7]))

#define PUT_UINT64(p, i)           \
    do {                             \
        (p)[0] = ((i) >> 56) & 0xff; \
        (p)[1] = ((i) >> 48) & 0xff; \
        (p)[2] = ((i) >> 40) & 0xff; \
        (p)[3] = ((i) >> 32) & 0xff; \
        (p)[4] = ((i) >> 24) & 0xff; \
        (p)[5] = ((i) >> 16) & 0xff; \
        (p)[6] = ((i) >> 8) & 0xff;  \
        (p)[7] = (i) & 0xff;         \
    } while(0)

#define ROTL32(n, x) (((x) << (n)) | ((x) >> ((-(n) & 31))))
#define ROTL64(n, x) (((x) << (n)) | ((x) >> ((-(n)) & 63)))

#define Choice(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
/* #define Majority(x,y,z) ( ((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)) ) */
#define Majority(x, y, z) (((x) & (y)) ^ ((z) & ((x) ^ (y))))

#define MD_UPDATE(ctx, length, data, f, incr)                           \
    do {                                                                \
        if((ctx)->index) {                                              \
            /* Try to fill partial block */                             \
            unsigned __md_left = sizeof((ctx)->block) - (ctx)->index;   \
            if((length) < __md_left) {                                  \
                memcpy((ctx)->block + (ctx)->index, (data), (length));  \
                (ctx)->index += (length);                               \
                goto __md_done; /* Finished */                          \
            } else {                                                    \
                memcpy((ctx)->block + (ctx)->index, (data), __md_left); \
                                                                        \
                f((ctx), (ctx)->block);                                 \
                (incr);                                                 \
                                                                        \
                (data) += __md_left;                                    \
                (length) -= __md_left;                                  \
            }                                                           \
        }                                                               \
        while((length) >= sizeof((ctx)->block)) {                       \
            f((ctx), (data));                                           \
            (incr);                                                     \
                                                                        \
            (data) += sizeof((ctx)->block);                             \
            (length) -= sizeof((ctx)->block);                           \
        }                                                               \
        memcpy((ctx)->block, (data), (length));                         \
        (ctx)->index = (length);                                        \
__md_done:;                                                             \
    } while(0)

#define MD_PAD(ctx, size, f)                                                 \
    do {                                                                     \
        unsigned __md_i;                                                     \
        __md_i = (ctx)->index;                                               \
                                                                             \
        /* Set the first char of padding to 0x80. This is safe since there   \
           is always at least one byte free */                               \
                                                                             \
        assert(__md_i < sizeof((ctx)->block));                               \
        (ctx)->block[__md_i++] = 0x80;                                       \
                                                                             \
        if(__md_i > (sizeof((ctx)->block) -                                  \
                        (size))) { /* No room for length in this block.      \
                                  Process it and pad with another one */     \
            memset((ctx)->block + __md_i, 0, sizeof((ctx)->block) - __md_i); \
                                                                             \
            f((ctx), (ctx)->block);                                          \
            __md_i = 0;                                                      \
        }                                                                    \
        memset(                                                              \
            (ctx)->block + __md_i, 0, sizeof((ctx)->block) - (size)-__md_i); \
                                                                             \
    } while(0)

#endif
